package com.four.secondcache;

import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author yangl
 * @version 1.0
 * @date 2022/11/18 9:51
 *
 * 数据查询顺序：二级缓存 -> 一级缓存（脏数据） -> 数据库
 * 使用 @Autowired 会注入失败，使用 applicationContext 对象来获取
 */

public class RedisCache implements Cache {
    //id：<mapper namespace="com.qf.mapper.xxxMapper" >
    private String id;

    //RedisTemplate 对象
    private RedisTemplate redisTemplate;

    //读写锁，大家都可以读数据，一旦有写的操作，不能再有其他读写操作了
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    //获取 RedisTemplate 对象，使用单例模式中的双重校验锁模式
    public RedisTemplate getRedisTemplate(){
        //先检查当前实例是否为空，如果不存在再进行同步
        if(null == redisTemplate){
            //同步
            synchronized (RedisCache.class) {
                //再次检查当前实例是否为空
                if(null == redisTemplate){
                    //返回
                    redisTemplate = ApplicationContextHolder.getRedisTemplate();
                    //设置key序列化方式
                    redisTemplate.setKeySerializer(RedisSerializer.string());
                    return redisTemplate;
                }
            }
        }
        return redisTemplate;
    }

    public RedisCache(String id) {
        System.out.println("id：" + id);
        this.id = id;
    }

    //获取 namespace
    @Override
    public String getId() {
        System.out.println("getId()：" + id);
        return id;
    }

    //存数据到缓存中
    @Override
    public void putObject(Object key, Object value) {
        //键一般设置成String类型
        getRedisTemplate().opsForValue().set(key.toString(),value);
    }

    //获取缓存中的数据
    @Override
    public Object getObject(Object key) {
        //取数据的时候，键也是String类型
        return getRedisTemplate().opsForValue().get(key.toString());
    }

    //从缓存中移除数据
    @Override
    public Object removeObject(Object key) {
        return getRedisTemplate().delete(key.toString());
    }

    //清除缓存
    @Override
    public void clear() {
        Set keys = redisTemplate.keys("*" + id + "*");
        redisTemplate.delete(keys);
    }

    //获取缓存数据的长度
    @Override
    public int getSize() {
        Set keys = redisTemplate.keys("*" + id + "*");
        return keys.size();
    }

    //读写锁
    @Override
    public ReadWriteLock getReadWriteLock() {
        return readWriteLock;
    }
}
